<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <meta charset="utf-8" />
    <title>几何最优化演示 - FE+EB最小值问题</title>
    
    <script src="https://www.geogebra.org/apps/deployggb.js"></script>
    <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
    <link href="https://fonts.googleapis.com/css2?family=Noto+Sans+SC:wght@400;500;700&display=swap" rel="stylesheet">

    <style>
        :root {
            --primary-color: #4285f4;
            --secondary-color: #34a853;
            --accent-color: #ea4335;
            --text-color: #333;
            --bg-color: #f5f9ff;
            --panel-bg: #ffffff;
            --border-color: #ddd;
            --shadow: 0 2px 10px rgba(0,0,0,0.1);
        }
        
        * {
            box-sizing: border-box;
            margin: 0;
            padding: 0;
        }
        
        body, html {
            font-family: 'Noto Sans SC', sans-serif;
            height: 100%;
            width: 100%;
            overflow: hidden;
            background-color: var(--bg-color);
            color: var(--text-color);
        }
        
        .container {
            display: flex;
            flex-direction: column;
            height: 100vh;
            width: 100%;
        }
        
        .header {
            background: linear-gradient(135deg, var(--primary-color), #3a7bd5);
            color: white;
            padding: 15px 20px;
            box-shadow: var(--shadow);
            z-index: 10;
        }
        
        .header h1 {
            font-size: 1.5rem;
            font-weight: 500;
        }
        
        .header p {
            font-size: 0.9rem;
            opacity: 0.9;
            margin-top: 5px;
        }
        
        .content {
            display: flex;
            flex: 1;
            overflow: hidden;
        }
        
        .geogebra-section {
            flex: 1;
            display: flex;
            min-width: 0;
        }
        
        .ggb-container {
            flex: 1;
            min-height: 0;
            border-right: 1px solid var(--border-color);
            background: white;
        }
        
        #ggbApplet {
            width: 100%;
            height: 100%;
        }
        
        .control-panel {
            width: 320px;
            background-color: var(--panel-bg);
            padding: 20px;
            overflow-y: auto;
            box-shadow: -2px 0 5px rgba(0,0,0,0.05);
            display: flex;
            flex-direction: column;
            gap: 25px;
        }
        
        .panel-section {
            padding-bottom: 15px;
            border-bottom: 1px solid var(--border-color);
        }
        
        .panel-section h2 {
            font-size: 1.2rem;
            margin-bottom: 15px;
            color: var(--primary-color);
            display: flex;
            align-items: center;
            gap: 8px;
        }
        
        .panel-section h2 i {
            font-size: 1.1rem;
        }
        
        .slider-control {
            margin: 15px 0;
        }
        
        .slider-label {
            display: flex;
            justify-content: space-between;
            margin-bottom: 8px;
            font-size: 0.95rem;
        }
        
        .slider-value {
            font-weight: 500;
            color: var(--primary-color);
        }
        
        .slider {
            width: 100%;
            height: 8px;
            -webkit-appearance: none;
            background: #e0e0e0;
            border-radius: 4px;
            outline: none;
        }
        
        .slider::-webkit-slider-thumb {
            -webkit-appearance: none;
            width: 18px;
            height: 18px;
            border-radius: 50%;
            background: var(--primary-color);
            cursor: pointer;
            border: 2px solid white;
            box-shadow: 0 1px 3px rgba(0,0,0,0.2);
        }
        
        .metric-display {
            background-color: #f8f9fa;
            border-radius: 8px;
            padding: 15px;
            margin-top: 10px;
        }
        
        .metric-row {
            display: flex;
            justify-content: space-between;
            padding: 8px 0;
            border-bottom: 1px dashed #e0e0e0;
        }
        
        .metric-row:last-child {
            border-bottom: none;
        }
        
        .metric-label {
            display: flex;
            align-items: center;
            gap: 8px;
        }
        
        .metric-value {
            font-weight: 500;
        }
        
        .buttons {
            display: flex;
            gap: 10px;
            margin-top: 15px;
            flex-wrap: wrap;
        }
        
        .btn {
            padding: 8px 15px;
            border: none;
            border-radius: 6px;
            background: var(--primary-color);
            color: white;
            cursor: pointer;
            font-family: inherit;
            font-size: 0.9rem;
            display: flex;
            align-items: center;
            gap: 6px;
            transition: all 0.2s;
            box-shadow: 0 2px 4px rgba(0,0,0,0.1);
        }
        
        .btn:hover {
            opacity: 0.9;
            transform: translateY(-2px);
        }
        
        .btn i {
            font-size: 0.9rem;
        }
        
        .btn.reset {
            background: var(--accent-color);
        }
        
        .btn.animate {
            background: var(--secondary-color);
        }
        
        .solution {
            background: #e8f4ff;
            border-left: 4px solid var(--primary-color);
            padding: 15px;
            border-radius: 0 8px 8px 0;
            margin-top: 10px;
            font-size: 0.9rem;
        }
        
        .solution h3 {
            margin-bottom: 8px;
            color: var(--primary-color);
        }
        
        .min-value {
            font-weight: 700;
            font-size: 1.2rem;
            color: var(--secondary-color);
            text-align: center;
            margin: 10px 0;
        }
        
        @media (max-width: 768px) {
            .content {
                flex-direction: column;
            }
            
            .control-panel {
                width: 100%;
                height: auto;
            }
            
            .ggb-container {
                height: 60vh;
            }
        }
    </style>
</head>

<body>
    <div class="container">
        <div class="header">
            <h1><i class="fas fa-shapes"></i> 几何最优化演示</h1>
            <p>在直角三角形ACB中，∠C=90°，∠ABC=75°，AB=5。点E在AC上，点F在AB上，求FE+EB的最小值</p>
        </div>
        
        <div class="content">
            <div class="geogebra-section">
                <div class="ggb-container">
                    <div id="ggbApplet"></div>
                </div>
            </div>
            
            <div class="control-panel">
                <div class="panel-section">
                    <h2><i class="fas fa-sliders-h"></i> 点位置控制</h2>
                    
                    <div class="slider-control">
                        <div class="slider-label">
                            <span>E点在AC边上的位置</span>
                            <span class="slider-value" id="e-value">0.50</span>
                        </div>
                        <input type="range" min="0" max="1" step="0.01" value="0.5" class="slider" id="e-slider">
                    </div>
                    
                   
                    <div class="slider-control">
                        <div class="slider-label">
                            <span>F点在AB边上的位置</span>
                            <span class="slider-value" id="f-value">0.50</span>
                        </div>
                        <input type="range" min="0" max="1" step="0.01" value="0.5" class="slider" id="f-slider">
                    </div>
                </div>
                
                <div class="panel-section">
                    <h2><i class="fas fa-ruler"></i> 距离测量</h2>
                    <div class="metric-display">
                        <div class="metric-row">
                            <div class="metric-label">
                                <i class="fas fa-long-arrow-alt-right" style="color:#ea4335"></i>
                                <span>FE长度：</span>
                            </div>
                            <span class="metric-value" id="fe-value">0.00</span>
                        </div>
                        <div class="metric-row">
                            <div class="metric-label">
                                <i class="fas fa-long-arrow-alt-right" style="color:#4285f4"></i>
                                <span>EB长度：</span>
                            </div>
                            <span class="metric-value" id="eb-value">0.00</span>
                        </div>
                        <div class="metric-row">
                            <div class="metric-label">
                                <i class="fas fa-plus" style="color:#34a853"></i>
                                <span>FE + EB：</span>
                            </div>
                            <span class="metric-value" id="sum-value">0.00</span>
                        </div>
                    </div>
                </div>
                
                <div class="panel-section">
                    <h2><i class="fas fa-calculator"></i> 最小值计算</h2>
                    <div class="solution">
                        <h3><i class="fas fa-lightbulb"></i> 解题方法：</h3>
                        <p>作点B关于直线AC的对称点B'，则FE+EB=FE+EB'。当F、E、B'三点共线且B'F垂直于AB时，路径最短。</p>
                        <div class="min-value">最小值 = <span id="min-value">2.50</span></div>
                    </div>
                    <div class="buttons">
                        <button class="btn animate" id="animate-btn">
                            <i class="fas fa-play"></i> 动画演示
                        </button>
                        <button class="btn" id="min-btn">
                            <i class="fas fa-bullseye"></i> 显示最小值
                        </button>
                        <button class="btn reset" id="reset-btn">
                            <i class="fas fa-redo"></i> 重置
                        </button>
                    </div>
                </div>
                
                <div class="panel-section">
                    <h2><i class="fas fa-project-diagram"></i> 路径追踪</h2>
                    <p>开启轨迹追踪可查看FE+EB随点位置变化的情况</p>
                    <div class="buttons">
                        <button class="btn" id="trace-btn">
                            <i class="fas fa-braille"></i> 切换轨迹追踪
                        </button>
                    </div>
                </div>
            </div>
        </div>
    </div>
    
    <script>       
        const parameters = {
            "id": "ggbApplet",
            "width": 800,
            "height": 600,
            "showMenuBar": false,
            "showAlgebraInput": false,
            "showToolBar": true,
            "showToolBarHelp": false,
            "showResetIcon": false,
            "enableLabelDrags": true,
            "enableShiftDragZoom": true,
            "enableRightClick": true,
            "errorDialogsActive": false,
            "useBrowserForJS": true,
            "allowStyleBar": true,
            "preventFocus": false,
            "showZoomButtons": true,
            "capturingThreshold": 3,
            "showFullscreenButton": true,
            "scale": 1,
            "disableAutoScale": false,
            "allowUpscale": false,
            "clickToLoad": false,
            "appName": "classic",
            "buttonRounding": 0.7,
            "buttonShadows": false,
            "language": "zh-CN",
            "appletOnLoad": function(api) {
                // 使用局部变量而不是全局变量
                const ggb = api;
                
                // 初始调整大小
                resizeApplet();
                
                // 窗口大小改变时重新调整大小
                window.addEventListener('resize', resizeApplet);
                
                // 初始化几何构造
                initializeConstruction(ggb);
                
                // 设置UI事件监听
                setupEventListeners(ggb);
            }
        };

        // 调整GeoGebra应用大小
        function resizeApplet() {
            const container = document.querySelector('.ggb-container');
            if (container) {
                const width = container.offsetWidth;
                const height = container.offsetHeight;
                
                // 如果应用已加载，调整大小
                if (typeof ggb !== 'undefined' && ggb && typeof ggb.setSize === 'function') {
                    ggb.setSize(width, height);
                }
            }
        }

        // 初始化几何构造
        function initializeConstruction(ggb) {
            // 创建直角三角形ACB (∠C=90°, ∠ABC=75°, AB=5)
            ggb.evalCommand('A = (0, 0)');
            ggb.evalCommand('B = (5, 0)');
            
            // 计算点C的位置（使用三角函数）
            const angleABC = 75 * Math.PI / 180;
            const angleBAC = 15 * Math.PI / 180;
            const cy = 5 * Math.sin(angleABC)* Math.cos(angleABC);
            const cx = 5 * Math.sin(angleABC)* Math.sin(angleABC);
            
            // 设置C点坐标（正确位置）
            ggb.evalCommand(`C = (${cx}, ${cy})`);
            
            // 创建三角形
            ggb.evalCommand('tri = Polygon(A, B, C)');
            
            // 创建对称点B'（B关于AC的对称点）
            ggb.evalCommand('Bp = Reflect(B, Line(A, C))');
            ggb.setLabelVisible('Bp', false);
            
            // 创建最优路径构造
            ggb.evalCommand('perp = PerpendicularLine(Bp, Line(A, B))');
            ggb.evalCommand('F0 = Intersect(perp, Line(A, B))');
            ggb.evalCommand('E0 = Intersect(Line(A, C), Line(Bp, F0))');
            
            // 创建可移动点
            ggb.evalCommand('E = Point(Line(A, C))');
            ggb.evalCommand('F = Point(Line(A, B))');
            
            // 使用新的方式获取点坐标
            const e0 = {x: ggb.getXcoord('E0'), y: ggb.getYcoord('E0')};
            const f0 = {x: ggb.getXcoord('F0'), y: ggb.getYcoord('F0')};
            
            // 设置初始位置
            ggb.evalCommand(`SetCoords(E, ${e0.x}, ${e0.y})`);
            ggb.evalCommand(`SetCoords(F, ${f0.x}, ${f0.y})`);
            
            // 创建线段
            ggb.evalCommand('fe = Segment(F, E)');
            ggb.evalCommand('eb = Segment(E, B)');
            ggb.evalCommand('minPath = Segment(F0, E0)');
            ggb.evalCommand('minPath2 = Segment(E0, B)');
            
            // 设置样式
            ggb.setColor('fe', 234, 67, 53);  // 红色
            ggb.setLineThickness('fe', 3);
            ggb.setColor('eb', 66, 133, 244);  // 蓝色
            ggb.setLineThickness('eb', 3);
            ggb.setColor('minPath', 52, 168, 83);  // 绿色
            ggb.setColor('minPath2', 52, 168, 83);
            ggb.setLineThickness('minPath', 3);
            ggb.setLineThickness('minPath2', 3);
            ggb.setVisible('minPath', false);
            ggb.setVisible('minPath2', false);
            
            // 创建轨迹追踪
            ggb.evalCommand('locus = Locus(E, F)');
            ggb.setColor('locus', 155, 155, 155);
            ggb.setLineThickness('locus', 1);
            ggb.setVisible('locus', false);
            
            // 设置最小距离文本
            const minDist = ggb.getValue('Distance(F0, E0) + Distance(E0, B)');
            document.getElementById('min-value').textContent = minDist.toFixed(2);
            
            // 隐藏构造辅助线
            ggb.setVisible('perp', false);
            ggb.setVisible('Bp', false);
        }

        // 设置事件监听器
        function setupEventListeners(ggb) {
            // 滑块控制点位置
            const eSlider = document.getElementById('e-slider');
            const fSlider = document.getElementById('f-slider');
            const eValue = document.getElementById('e-value');
            const fValue = document.getElementById('f-value');
            
            eSlider.addEventListener('input', function() {
                const value = parseFloat(this.value);
                eValue.textContent = value.toFixed(2);
                
                // 更新E点位置
                const a = {x: ggb.getXcoord('A'), y: ggb.getYcoord('A')};
                const c = {x: ggb.getXcoord('C'), y: ggb.getYcoord('C')};
                const newX = a.x + value * (c.x - a.x);
                const newY = a.y + value * (c.y - a.y);
                ggb.evalCommand(`SetCoords(E, ${newX}, ${newY})`);
                
                updateMeasurements(ggb);
            });
            
            fSlider.addEventListener('input', function() {
                const value = parseFloat(this.value);
                fValue.textContent = value.toFixed(2);
                
                // 更新F点位置
                const a = {x: ggb.getXcoord('A'), y: ggb.getYcoord('A')};
                const b = {x: ggb.getXcoord('B'), y: ggb.getYcoord('B')};
                const newX = a.x + value * (b.x - a.x);
                const newY = a.y + value * (b.y - a.y);
                ggb.evalCommand(`SetCoords(F, ${newX}, ${newY})`);
                
                updateMeasurements(ggb);
            });
            
            // 重置按钮
            document.getElementById('reset-btn').addEventListener('click', function() {
                const e0 = {x: ggb.getXcoord('E0'), y: ggb.getYcoord('E0')};
                const f0 = {x: ggb.getXcoord('F0'), y: ggb.getYcoord('F0')};
                
                ggb.evalCommand(`SetCoords(E, ${e0.x}, ${e0.y})`);
                ggb.evalCommand(`SetCoords(F, ${f0.x}, ${f0.y})`);
                
                // 计算标准化位置
                const a = {x: ggb.getXcoord('A'), y: ggb.getYcoord('A')};
                const c = {x: ggb.getXcoord('C'), y: ggb.getYcoord('C')};
                const b = {x: ggb.getXcoord('B'), y: ggb.getYcoord('B')};
                
                const eVal = (e0.y - a.y) / (c.y - a.y);
                const fVal = (f0.x - a.x) / (b.x - a.x);
                
                eSlider.value = eVal;
                fSlider.value = fVal;
                eValue.textContent = eVal.toFixed(2);
                fValue.textContent = fVal.toFixed(2);
                
                ggb.setVisible('minPath', false);
                ggb.setVisible('minPath2', false);
                ggb.setVisible('locus', false);
                
                updateMeasurements(ggb);
            });
            
            // 动画演示按钮
            document.getElementById('animate-btn').addEventListener('click', function() {
                animateOptimalPath(ggb);
            });
            
            // 最小值按钮
            document.getElementById('min-btn').addEventListener('click', function() {
                showMinimumPath(ggb);
            });
            
            // 轨迹追踪按钮
            document.getElementById('trace-btn').addEventListener('click', function() {
                const isVisible = ggb.getVisible('locus');
                ggb.setVisible('locus', !isVisible);
                
                // 清除轨迹
                if (!isVisible) {
                    ggb.evalCommand('UpdateConstruction()');
                }
            });
        }
        
        // 更新测量值
        function updateMeasurements(ggb) {
            const fe = ggb.getValue('Distance(F, E)');
            const eb = ggb.getValue('Distance(E, B)');
            const sum = fe + eb;
            
            document.getElementById('fe-value').textContent = fe.toFixed(2);
            document.getElementById('eb-value').textContent = eb.toFixed(2);
            document.getElementById('sum-value').textContent = sum.toFixed(2);
        }
        
        // 动画演示最优路径
        function animateOptimalPath(ggb) {
            const steps = 40;
            const duration = 2500;
            const stepTime = duration / steps;
            
            // 使用新的方式获取点坐标
            const startE = {x: ggb.getXcoord('E'), y: ggb.getYcoord('E')};
            const startF = {x: ggb.getXcoord('F'), y: ggb.getYcoord('F')};
            const endE = {x: ggb.getXcoord('E0'), y: ggb.getYcoord('E0')};
            const endF = {x: ggb.getXcoord('F0'), y: ggb.getYcoord('F0')};
            
            const eSlider = document.getElementById('e-slider');
            const fSlider = document.getElementById('f-slider');
            const eValue = document.getElementById('e-value');
            const fValue = document.getElementById('f-value');
            
            let step = 0;
            const animation = setInterval(() => {
                if (step >= steps) {
                    clearInterval(animation);
                    ggb.setVisible('minPath', true);
                    ggb.setVisible('minPath2', true);
                    return;
                }
                
                const ratio = easeInOutCubic(step / steps);
                
                // 计算中间点坐标
                const eX = startE.x + (endE.x - startE.x) * ratio;
                const eY = startE.y + (endE.y - startE.y) * ratio;
                const fX = startF.x + (endF.x - startF.x) * ratio;
                const fY = startF.y + (endF.y - startF.y) * ratio;
                
                // 更新点位置
                ggb.evalCommand(`SetCoords(E, ${eX}, ${eY})`);
                ggb.evalCommand(`SetCoords(F, ${fX}, ${fY})`);
                
                // 更新滑块显示
                const a = {x: ggb.getXcoord('A'), y: ggb.getYcoord('A')};
                const c = {x: ggb.getXcoord('C'), y: ggb.getYcoord('C')};
                const b = {x: ggb.getXcoord('B'), y: ggb.getYcoord('B')};
                
                const eVal = (eY - a.y) / (c.y - a.y);
                const fVal = (fX - a.x) / (b.x - a.x);
                
                eSlider.value = eVal;
                fSlider.value = fVal;
                eValue.textContent = eVal.toFixed(2);
                fValue.textContent = fVal.toFixed(2);
                
                updateMeasurements(ggb);
                step++;
            }, stepTime);
        }
        
        // 显示最小路径
        function showMinimumPath(ggb) {
            // 使用新的方式获取点坐标
            const e0 = {x: ggb.getXcoord('E0'), y: ggb.getYcoord('E0')};
            const f0 = {x: ggb.getXcoord('F0'), y: ggb.getYcoord('F0')};
            
            ggb.evalCommand(`SetCoords(E, ${e0.x}, ${e0.y})`);
            ggb.evalCommand(`SetCoords(F, ${f0.x}, ${f0.y})`);
            
            // 更新滑块位置
            const a = {x: ggb.getXcoord('A'), y: ggb.getYcoord('A')};
            const c = {x: ggb.getXcoord('C'), y: ggb.getYcoord('C')};
            const b = {x: ggb.getXcoord('B'), y: ggb.getYcoord('B')};
            
            const eVal = (e0.y - a.y) / (c.y - a.y);
            const fVal = (f0.x - a.x) / (b.x - a.x);
            
            document.getElementById('e-slider').value = eVal;
            document.getElementById('f-slider').value = fVal;
            document.getElementById('e-value').textContent = eVal.toFixed(2);
            document.getElementById('f-value').textContent = fVal.toFixed(2);
            
            // 显示最小路径
            ggb.setVisible('minPath', true);
            ggb.setVisible('minPath2', true);
            
            updateMeasurements(ggb);
        }
        
        // 缓动函数（平滑动画）
        function easeInOutCubic(t) {
            return t < 0.5 ? 4 * t * t * t : 1 - Math.pow(-2 * t + 2, 3) / 2;
        }

        // 初始化GeoGebra Applet
        function initGeoGebra() {
            const applet = new GGBApplet(parameters, true);
            applet.inject('ggbApplet');
        }
        
        // 页面加载完成后初始化
        document.addEventListener('DOMContentLoaded', () => {
            initGeoGebra();
        });
        
        // 处理窗口大小变化
        window.addEventListener('resize', resizeApplet);
    </script>
</body>
</html>